/******************************************************************
 * This program was written as part of
 *   Assignment 4
 *   Computer Graphics                                             
 *   Semester 1, 2013
 *   School of Computer Science,
 *   The University of Adelaide
 *                                                                          
 * I declare that all material in this assessment is my own work except where
 * there is clear acknowledgement and reference to the work of others. I have
 * read the University Policy Statement on Plagiarism, Collusion and Related
 * Forms of Cheating:  

 * http://www.adelaide.edu.au/policies/?230

 * I give permission for my assessment work, including my subversion
 * repository, to be reproduced and submitted to academic staff for the
 * purposes of assessment and to be copied, submitted and retained in a form
 * suitable for electronic checking of plagiarism.  
                            
 * Authors:
 *  Terry Moschou    a1208955
 *  Salih Al-Rashid  a1210108
 *  Ben McAleer      a1212203
*******************************************************************/

#include "Enemy.hpp"

#include "Model.hpp"
#include "Material.hpp"

#include "Context.hpp"
#include "Scene.hpp"
#include "Terrain.hpp"

#define PI 3.14
#define GRAVY 0.05
#define GENHEIGHT 5.0

Enemy::Enemy(Object * parent /* = 0 */, Model * model, int type,
               const glm::mat4 & modelMatrix /* = glm::mat4(1.0f) */)
  : Object(parent, modelMatrix, model, "Enemy")
{
  m_type = type;
  m_step = 0;
  
  if(m_type == NAVI) {
    Model * m_m = new Model("resources/models/wings.obj");
    w1 = new Object(this,mat4(1.0f),m_m,"Player Wings");
    w2 = new Object(this,mat4(1.0f),m_m,"Player Wings");
    m_name = "Player Fairy";
  }
  
}

void Enemy::specificUpdate() {
  m_step++;
  switch(m_type) {
    case THWOMP: thwomp(); break;
    case FISH: fish(); break;
    case NAVI: navi(); break;
  }
}

void Enemy::update() {
  
  specificUpdate();
  //Transformation
  mat4 transform = glm::rotate(glm::translate(mat4(1.0f), m_pos), m_rot, vec3(0.0f, 1.0f, 0.0f));
  setModelMatrix(transform);
  
  Object::update();
  
}

void Enemy::thwomp() {
  
  if(m_step%300 < 10) {
    m_pos.y -= 8.0/10.0;
  }
  
  if(m_step%300 >= 50 && m_step%300 < 100) {
    m_pos.y += 8.0/50.0;
  }
  
}

void Enemy::fish() {
  
  m_rot = (m_step%800)*360/800;
  m_pos.x += 0.05f*sin(m_rot*PI/180);
  m_pos.z += 0.05f*cos(m_rot*PI/180);
  
}

void Enemy::navi() {
  

  mat4 w1t = glm::rotate(mat4(1.0f), 40.0f*(float)cos(m_step/3.0), vec3(0.0f, 1.0f, 0.0f));
  w1->setModelMatrix(w1t);
  mat4 w2t = glm::rotate(mat4(1.0f), -40.0f*(float)cos(m_step/3.0), vec3(0.0f, 1.0f, 0.0f));
  w2->setModelMatrix(w2t);
  
  
}

void Enemy::draw(const glm::mat4 & modelMatrix)
{
  
  
  
  if(m_type == NAVI) {
    //Object::draw(modelMatrix);
    
    if(!stoppit) {
      m_pos.x += 0.25*cos((m_step%360)*PI/180);
      m_pos.z += 0.25*sin((m_step%360)*PI/180);
    }
    m_pos.y += 0.25*sin(5*(m_step%360)*PI/180);

    
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    glm::mat4 newModelMatrix;
    Program * program;
    
        //2D wings
    program = g_context.useProgram(Context::Wings);
    
    newModelMatrix = getModelMatrix() * modelMatrix * w1->m_modelMatrix;
    
    glUniformMatrix4fv(w1->m_model->m_ul_model, 1, false,
                         &newModelMatrix[0][0]);
    
    glBindVertexArray(w1->m_model->m_vaoHandle);
    
    for (int m = 0; m < w1->m_model->m_materialCount; ++m) {
    
    glUniform3fv(w1->m_model->m_ul_Ka, 1, &w2->m_model->m_materials[m].m_ambient[0]);
    glUniform3fv(w1->m_model->m_ul_Kd, 1, &w1->m_model->m_materials[m].m_diffuse[0]);
    glUniform3fv(w1->m_model->m_ul_Ks, 1, &w1->m_model->m_materials[m].m_specular[0]);
    glUniform1f(w1->m_model->m_ul_s, w1->m_model->m_materials[m].m_shininess);
    
    if (w1->m_model->m_materials[m].m_hasTexture) {
      glBindTexture(GL_TEXTURE_2D, w1->m_model->m_materials[m].m_tboHandle);
    }program = g_context.useProgram(Context::Wings);

    glDrawArrays(GL_TRIANGLES, w1->m_model->m_materials[m].m_offset,
                 w1->m_model->m_materials[m].m_vertexCount);
    }
    
    newModelMatrix = getModelMatrix() * modelMatrix * w2->m_modelMatrix;
    glUniformMatrix4fv(w2->m_model->m_ul_model, 1, false,
                         &newModelMatrix[0][0]);
    
    glBindVertexArray(w2->m_model->m_vaoHandle);
    
    for (int m = 0; m < w2->m_model->m_materialCount; ++m) {
    
    glUniform3fv(w2->m_model->m_ul_Ka, 1, &w2->m_model->m_materials[m].m_ambient[0]);
    glUniform3fv(w2->m_model->m_ul_Kd, 1, &w2->m_model->m_materials[m].m_diffuse[0]);
    glUniform3fv(w2->m_model->m_ul_Ks, 1, &w2->m_model->m_materials[m].m_specular[0]);
    glUniform1f(w2->m_model->m_ul_s, w2->m_model->m_materials[m].m_shininess);
    
    if (w2->m_model->m_materials[m].m_hasTexture) {
      glBindTexture(GL_TEXTURE_2D, w2->m_model->m_materials[m].m_tboHandle);
    }

    glDrawArrays(GL_TRIANGLES, w2->m_model->m_materials[m].m_offset,
                 w2->m_model->m_materials[m].m_vertexCount);
    }
    
    //fairy
    program = g_context.useProgram(Context::Fairy);
    newModelMatrix = modelMatrix * m_modelMatrix;
    glUniformMatrix4fv(m_model->m_ul_model, 1, false,
                         &newModelMatrix[0][0]);
    
    glBindVertexArray(m_model->m_vaoHandle);
    
    for (int m = 0; m < m_model->m_materialCount; ++m) {
    
    glUniform3fv(m_model->m_ul_Ka, 1, &m_model->m_materials[m].m_ambient[0]);
    glUniform3fv(m_model->m_ul_Kd, 1, &m_model->m_materials[m].m_diffuse[0]);
    glUniform3fv(m_model->m_ul_Ks, 1, &m_model->m_materials[m].m_specular[0]);
    glUniform1f(m_model->m_ul_s, m_model->m_materials[m].m_shininess);
    
    if (m_model->m_materials[m].m_hasTexture) {
      glBindTexture(GL_TEXTURE_2D, m_model->m_materials[m].m_tboHandle);
    }

    glDrawArrays(GL_TRIANGLES, m_model->m_materials[m].m_offset,
                 m_model->m_materials[m].m_vertexCount);
    }
    

    
    glDisable(GL_BLEND);
    glBindVertexArray(0);
    

  } else {
    Object::draw(modelMatrix);
  }
    
  
}
